package com.hmall.common.utils;

import cn.hutool.core.lang.UUID;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.concurrent.ListenableFutureCallback;

@RequiredArgsConstructor
@Slf4j
public class RabbitMqHelper {
    private final RabbitTemplate rabbitTemplate;
    //发消息的方法
    public void sendMessage(String exchange,String routingKey,Object msg){
        log.debug("准备发送消息，exchange：{}，routingKey：{}，msg：{}",exchange,routingKey,msg);
        rabbitTemplate.convertAndSend(exchange,routingKey,msg);
    }
    //发延时消息的方法
    public void sendDelayedMessage(String exchange,String routingKey,Object msg,int delayMili){
        log.debug("准备发送消息，exchange：{}，routingKey：{}，msg：{}",exchange,routingKey,msg);
        rabbitTemplate.convertAndSend(exchange,routingKey,message -> {
            message.getMessageProperties().setDelay(delayMili);
            return message;
        });
    }
    //带确认的消息发送方法
    public void sendMessageWithConfirm(String exchange,String routingKey,Object msg){
        log.debug("准备发送消息，exchange：{}，routingKey：{}，msg：{}",exchange,routingKey,msg);
        //准备发送的数据，这里是确认机制的对象
        CorrelationData cd = new CorrelationData();
        cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
            //这里还有重试的功能，在重试时下边把这个callback又添加到新的cd中了，所以可以在这里记录重试次数
            int retryTimes;  //自动初始化为0
            @Override
            public void onFailure(Throwable ex) {
                //失败的处理逻辑
                //这个是返回的这个callback处理的时候失败了
                log.error("处理Ack回执失败",ex);
            }

            @Override
            public void onSuccess(CorrelationData.Confirm result) {
                //处理回执成功了，但是还要解析一下里边是不是ack
                if(result!=null&&!result.isAck()){
                    log.error("消息发送失败，收到NACK，已重试次数：{}",retryTimes);
                    if(retryTimes>=3){
                        log.error("重试次数已耗尽");
                        return;
                    }
                    //还能重试的话
                    //每次都生成一个新的消息id，把原有的callback加到新的cd中，里边记录着重试次数
                    CorrelationData cd = new CorrelationData(UUID.randomUUID().toString(true));
                    cd.getFuture().addCallback(this);
                    rabbitTemplate.convertAndSend(exchange,routingKey,msg,cd);
                    retryTimes++;
                }
            }
        });
        rabbitTemplate.convertAndSend(exchange,routingKey,msg,cd);
    }
}
